package jdklearning.concurrent.thread.interrupt;


import java.util.concurrent.locks.ReentrantLock;

/**
 * 一看到线程的interrupt()方法，根据字面意思，很容易将该方法理解为中断线程
 * 。其实Thread.interrupt()并不会中断线程的运行，它的作用仅仅是为线程设定一个状态而已
 * ，即标明线程是中断状态，这样线程的调度机制或我们的代码逻辑就可以通过判断这个状态做一些处理
 * ，比如sleep()方法会抛出异常，或是我们根据isInterrupted()方法判断线程是否处于中断状态，然后做相关的逻辑处理。
 *
 * interrupt, 只是给线程发个信号，如果在wait, sleep,lockInterruptibly会收到exception
 * @author shenenlu 2021年02月20日 上午09:48:53
 */
public class InterruptLearning {


    /**
     * 处于阻塞的线程，即在执行Object对象的wait()、wait(long)、wait(long, int)，或者线程类的join()、join(long)、join(long, int)、sleep(long)、sleep(long,int)方法后线程的状态
     * ，当线程调用interrupt()方法后，这些方法将抛出InterruptedException异常，并清空线程的中断状态，即isInterrupted()返回false
     *
     * 任务运行中的线程不会响应中断,但是isInterrupted()会返回true
     */
    public static void interrupt1(){
        //sleepThread睡眠1000ms
        final Thread sleepThread = new Thread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    System.out.println("interrupt");
                    e.printStackTrace();
                }
                System.out.println("go on");
                super.run();
            }
        };
        //busyThread一直执行死循环
        Thread busyThread = new Thread() {
            @Override
            public void run() {
                while (true) ;
            }
        };
        sleepThread.start();
        busyThread.start();
        sleepThread.interrupt();
        busyThread.interrupt();
        while (sleepThread.isInterrupted()){

        }
        System.out.println("sleepThread isInterrupted: " + sleepThread.isInterrupted());
        System.out.println("busyThread isInterrupted: " + busyThread.isInterrupted());
    }

    /**
     *  如果一个线程处于了阻塞状态（如线程调用了thread.sleep、thread.join、thread.wait、1.5中的condition.await、以及可中断的通道上的 I/O 操作方法后可进入阻塞状态）
     *  ，则线程会一直检查中断状态标示，如果发现中断状态标示为true，则会在这些阻塞方法
     *  （sleep、join、wait、1.5中的condition.await及可中断的通道上的 I/O 操作方法）
     *  调用处抛出InterruptedException异常，并且在抛出异常后立即将线程的中断标示位清除，
     *  即重新设置为false。抛出异常是为了线程从阻塞状态醒过来，
     *  并在结束线程前让程序员有足够的时间来处理中断请求。
     *
     * 注，synchronized在获锁的过程中是不能被中断的，意思是说如果产生了死锁
     * ，则不可能被中断（请参考后面的测试例子）
     * 。与synchronized功能相似的reentrantLock.lock()方法也是一样，它也不可中断的，
     * 即如果发生死锁，那么reentrantLock.lock()方法无法终止，如果调用时被阻塞，
     * 则它一直阻塞到它获取到锁为止。但是如果调用带超时的tryLock方法
     * reentrantLock.tryLock(long timeout, TimeUnit unit)，
     * 那么如果线程在等待时被中断，将抛出一个InterruptedException异常，
     * 这是一个非常有用的特性，因为它允许程序打破死锁。
     * 你也可以调用reentrantLock.lockInterruptibly()方法
     * ，它就相当于一个超时设为无限的tryLock方法。
     */
    public static void interrupt2(){
        Thread td = new Thread(new Runnable(){
            @Override
            public void run() {
                try {
                    Thread.sleep(100000L);
                } catch (InterruptedException e) {
                    System.out.println("线程是否处于中断状态" + Thread.currentThread().isInterrupted());
                    e.printStackTrace();
                    System.out.println("abc");
                }
                System.out.println("def");
            }
        });
        td.start();
        td.interrupt();
    }


    /**
     * 使用中断信号量中断非阻塞状态的线程
     * 中断线程最好的，最受推荐的方式是，使用共享变量（shared variable）发出信号
     * ，告诉线程必须停止正在运行的任务
     * 。线程必须周期性的核查这一变量，然后有秩序地中止任务。Example2描述了这一方式：
     */
    static class Example2 implements Runnable {
        volatile boolean stop = false;// 线程中断信号量
        @Override
        public void run() {
            // 每隔一秒检测一下中断信号量
            while (!stop) {
                System.out.println("Thread is running...");
                long time = System.currentTimeMillis();
                /*
                 * 使用while循环模拟 sleep 方法，这里不要使用sleep，否则在阻塞时会 抛
                 * InterruptedException异常而退出循环，这样while检测stop条件就不会执行，
                 * 失去了意义。
                 */
                while ((System.currentTimeMillis() - time < 1000)) {}
            }
            System.out.println("Thread exiting under request...");
        }
    }

    public static void example2() throws InterruptedException {
        final Example2 example2 = new Example2();
        Thread t = new Thread(example2);
        System.out.println("Starting thread...");
        t.start();
        Thread.sleep(3000);
        System.out.println("Asking thread to stop...");
        // 设置中断信号量
        example2.stop = true;
        Thread.sleep(3000);
        System.out.println("Stopping application...");
    }


    /**
     * 我们还可以使用共享信号量来替换!Thread.currentThread().isInterrupted()条件
     * ，但不如它简洁。
     */
    static class Example3 implements Runnable {
        @Override
        public void run() {
            // 每隔一秒检测是否设置了中断标示
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("Thread is running...");
                long time = System.currentTimeMillis();
                // 使用while循环模拟 sleep
                while ((System.currentTimeMillis() - time < 1000) ) {
                }
            }
            System.out.println("Thread exiting under request...");
        }
    }

    public static void example3() throws InterruptedException {
        final Example3 example3 = new Example3();
        Thread t = new Thread(example3);
        System.out.println("Starting thread...");
        t.start();
        Thread.sleep(3000);
        System.out.println("Asking thread to stop...");
        t.interrupt();
        Thread.sleep(3000);
        System.out.println("Stopping application...");
    }


    /**
     * 不可中断死锁
     */
    static void deadLock(Object lock1, Object lock2) {
        try {
            synchronized (lock1) {
//                Thread.sleep(10);// 不会在这里死掉
                Thread.sleep(30000L);// 不会在这里死掉
                synchronized (lock2) {// 会锁在这里，虽然阻塞了，但不会抛异常
                    System.out.println(Thread.currentThread());
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }


    /**
     * 不可中断死锁
     */
    public static void example4() throws InterruptedException {
        final Object lock1 = new Object();
        final Object lock2 = new Object();

        Thread thread1 = new Thread() {
            public void run() {
                deadLock(lock1, lock2);
            }
        };
        Thread thread2 = new Thread() {
            public void run() {
                // 注意，这里在交换了一下位置
                deadLock(lock2, lock1);
            }
        };
        System.out.println("Starting thread...");
        thread1.start();
        thread2.start();
        Thread.sleep(20);
        System.out.println("Interrupting thread...");
        thread1.interrupt();
        thread2.interrupt();
        //Thread.sleep(3000);
        System.out.println("Stopping application...");
    }


    /**
     * 可中断死锁
     */
    public static void example5() throws InterruptedException {
        final ReentrantLock lock1 = new ReentrantLock();
        final ReentrantLock lock2 = new ReentrantLock();

        Thread thread1 = new Thread() {
            public void run() {
                try {
                    lock1.lock();
//                    lock1.lockInterruptibly();
                    Thread.sleep(10L);
                    lock2.lock();
//                    lock2.lockInterruptibly();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    lock1.unlock();
                    lock2.unlock();
                }
            }
        };
        Thread thread2 = new Thread() {
            public void run() {
                try {
                    lock2.lock();
//                    lock2.lockInterruptibly();
                    Thread.sleep(10L);
                    lock1.lock();
//                    lock1.lockInterruptibly();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    lock2.unlock();
                    lock2.unlock();
                }
            }
        };
        System.out.println("Starting thread...");
        thread1.start();
        thread2.start();
//        Thread.sleep(20);
//        System.out.println("Interrupting thread...");
//        thread1.interrupt();
//        thread2.interrupt();
        Thread.sleep(3000);
        System.out.println("Stopping application...");
    }


    private static void interruptAndSleep() throws InterruptedException {

        Thread t = new Thread(){
            @Override
            public void run() {
                int i = 0;
//                try {
                    while (true) {
//                        System.out.println(i++);
                        if( i > 300){
//                            Thread.sleep(20000);
                        }
                    }
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
            }
        };
        t.start();
        new Thread(() -> {
            while (true){
                System.out.println(t.isInterrupted());
            }
        }).start();
        Thread.sleep(2000);
        t.interrupt();

    }






    public static void main(String[] args) throws InterruptedException {
//        interrupt1();
//        interrupt2();
//        example2();

//        example3();

//        example4();
//        example5();
        
        
        interruptAndSleep();
    }



}
